package com.zbl.zblproject.pay.controller;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayOpenAuthTokenAppRequest;
import com.alipay.api.response.AlipayOpenAuthTokenAppResponse;
import com.alipay.demo.trade.model.builder.AlipayTradeRefundRequestBuilder;
import com.alipay.demo.trade.model.result.AlipayF2FRefundResult;
import com.alipay.demo.trade.service.AlipayTradeService;
import com.github.wxpay.sdk.WXPay;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.zbl.zblproject.core.entity.AdminUser;
import com.zbl.zblproject.core.entity.Result;
import com.zbl.zblproject.core.mapper.AdminUserMapper;
import com.zbl.zblproject.core.utils.ResultUtil;
import com.zbl.zblproject.core.utils.StringUtil;
import com.zbl.zblproject.pay.entity.*;
import com.zbl.zblproject.pay.mapper.Pay;
import com.zbl.zblproject.pay.mapper.PayOrderItemMapper;
import com.zbl.zblproject.pay.service.PayService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;

/**
 * @author youlanqiang
 * @version 1.0
 * @date 2018/11/5
 */
@Api(tags = "支付接口")
@RestController
@RequestMapping("/pay")
public class PayController {


    private static final Logger logger = LoggerFactory.getLogger(PayController.class);

    @Autowired
    private PayOrderItemMapper payOrderItemMapper;

    @Autowired
    private PayService payService;

    @Autowired
    private AdminUserMapper userMapper;

    @Autowired
    private AlipayTradeService alipayTradeService;

    @Autowired
    private AlipayProperties aliPayProperties;

    @Autowired
    private WXPay wxPay;

    @Autowired
    private Pay pay;


    private List<PayOrder> parseOrders(int userId, String json) {
        //logger.info("json数值结构:{}", json);
        List<PayOrder> orders = new ArrayList<>();
        JSONArray array = JSONArray.parseArray(json);
        JSONObject object;
        List<PayOrderItem> items;
        for (int i = 0; i < array.size(); i++) {
            object = array.getJSONObject(i);

            PayOrder order = new PayOrder();

            order.setStatus(0);
            order.setDiscount(object.getBigDecimal("myDiscount"));
            order.setMode(object.getInteger("mode"));
            if (order.getMode() == 1 || order.getMode() == 2) {
                //支付宝或微信支付
                Preconditions.checkArgument(object.containsKey("payCode"), "线上订单必须传入线上订单号.");
                String payCode = object.getString("payCode");
                if (Strings.isNullOrEmpty(payCode)) {
                    throw new RuntimeException("线上订单必须传入线上订单号.");
                }
                order.setPayCode(payCode);
            }

            /**
             * 应收账款 receivable
             */
            order.setReceivable(object.getBigDecimal("singleMoney"));
            /**
             * 实收 officialReceipts
             */
            order.setOfficialReceipts(object.getBigDecimal("realmoney"));
            /**
             * 找零 changeNote
             */
            order.setChangeNote(object.getBigDecimal("payChange"));
            order.setUserId(userId);


            String time = object.getString("createTime");
            if (!StringUtil.isNullOrEmpty(time)) {
                order.setCreateTime(LocalDateTime.parse(time));
            } else {
                order.setCreateTime(LocalDateTime.now());
            }

            /**
             * 将物品单转化为 PayOrderItem
             */
            items = new ArrayList<>();
            JSONArray arrayOfTheItem = object.getJSONArray("goodsList");
            for (int f = 0; f < arrayOfTheItem.size(); f++) {
                JSONObject item = arrayOfTheItem.getJSONObject(f);
                PayOrderItem orderItem = new PayOrderItem();
                orderItem.setDiscount(new BigDecimal(1.0));
                orderItem.setGoodsId(item.getInteger("goodsId"));
                orderItem.setGoodsNum(item.getInteger("goodNum"));
                orderItem.setSinglePrice(item.getBigDecimal("marketPrice"));
                items.add(orderItem);
            }
            order.setItems(items);
            orders.add(order);
        }

        return orders;
    }

    @GetMapping("/online-order/{orderSn}")
    @ApiOperation("查询线上订单号")
    public Result onlineOrderSn(@ApiParam("订单号") @PathVariable String orderSn) {
        String onlineOrder = payService.getPayOrderOnlineOrder(orderSn);
        if (onlineOrder == null) {
            return ResultUtil.error("失败!");
        }
        return ResultUtil.success("成功!", onlineOrder);
    }


    @PostMapping("/base")
    @ApiOperation("订单支付")
    public Result basePay(@ApiParam("用户ID") @RequestParam("userId") int userId, @ApiParam("订单信息") @RequestParam("items") String items) {
        List<PayOrder> orders = parseOrders(userId, items);
        try {
            logger.info("收银订单创建 userId:{}", userId);
            AdminUser user = getUserById(userId);
            payService.createBaseOrders(user, orders);
        } catch (RuntimeException e) {
            return ResultUtil.error(e.getMessage());
        }
        return ResultUtil.success("成功!");
    }

    @RequestMapping("/alipay-return")
    @ApiOperation("支付宝回调接口")
    public void alipayRefund(HttpServletResponse response, HttpServletRequest request) {
        try {
            Map<String, String> params = new HashMap<String, String>();
            Map requestParams = request.getParameterMap();
            for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
                String name = (String) iter.next();
                String[] values = (String[]) requestParams.get(name);
                String valueStr = "";
                for (int i = 0; i < values.length; i++) {
                    valueStr = (i == values.length - 1) ? valueStr + values[i]
                            : valueStr + values[i] + ",";
                }
                //乱码解决，这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
                valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
                params.put(name, valueStr);
            }
            //获取支付宝的通知返回参数，可参考技术文档中页面跳转同步通知参数列表(以下仅供参考)//
            //支付宝用户号
            PrintWriter out = response.getWriter();

            String app_id = new String(request.getParameter("app_id").getBytes("ISO-8859-1"), "UTF-8");

            //获取第三方登录授权
            String alipay_app_auth = new String(request.getParameter("source").getBytes("ISO-8859-1"), "UTF-8");


            //第三方授权code
            String app_auth_code = new String(request.getParameter("app_auth_code").getBytes("ISO-8859-1"), "UTF-8");//获的第三方登录用户授权app_auth_code


            //使用auth_code换取接口access_token及用户userId
            //AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do","应用APPID",privateKey,"json","UTF-8",publicKey,"RSA2");//正常环境下的网关
            //AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipaydev.com/gateway.do", "沙箱环境下的应用APPID", privateKey, "json", "UTF-8", publicKey, "RSA2");//沙箱下的网关

            AlipayClient alipayClient = new DefaultAlipayClient(aliPayProperties.getGatewayUrl(), aliPayProperties.getAppid(),
                    aliPayProperties.getAppPrivateKey(), "json", "UTF-8", aliPayProperties.getAlipayPublicKey(), "RSA2");//沙箱下的网关

            AlipayOpenAuthTokenAppRequest requestLogin1 = new AlipayOpenAuthTokenAppRequest();
            requestLogin1.setBizContent("{" +
                    "\"grant_type\":\"authorization_code\"," +
                    "\"code\":\"" + app_auth_code + "\"" +
                    "}");

            //第三方授权
            AlipayOpenAuthTokenAppResponse responseToken = alipayClient.execute(requestLogin1);
            if (responseToken.isSuccess()) {
                out.write("app-id: " + responseToken.getAuthAppId() + "\n");
                out.write("auth-token: " + responseToken.getAppAuthToken() + "\n");
                out.write("user-id: " + responseToken.getUserId() + "\n");
            } else {
                out.write("调用失败" + "\n");
            }
        } catch (Exception e) {

        }

    }

    @PostMapping("/alipay/some-refund")
    @ApiOperation("支付宝退部分款")
    public Result refundByItem(@ApiParam("线上订单号") @RequestParam("orderNo") String orderNo,
                               @ApiParam("退款的商品") @RequestParam("itemIds") Long[] ids) {
        PayOrder order = payService.getOrderByOnlineSn(orderNo);
        if (order == null) {
            return ResultUtil.error("没有发现这个订单！");
        }
        List<PayOrderItem> items = payOrderItemMapper.selectBatchIds(Arrays.asList(ids));
        if (items.isEmpty()) {
            return ResultUtil.error("没有需要退款的商品");
        }

        BigDecimal total = payService.returnAlipayItems(items);
        //要退款的商品,计算出金额
        return null;
    }

    /**
     * 退款
     *
     * @param orderNo 商户订单号
     * @return
     */
    @PostMapping("/alipay/refund")
    @ApiOperation("支付宝退款")
    public Result refund(@ApiParam("线上订单号") @RequestParam("orderNo") String orderNo) {
        PayOrder order = payService.getOrderByOnlineSn(orderNo);
        if (order == null) {
            return ResultUtil.error("没有发现这个订单！");
        }
        AlipayTradeRefundRequestBuilder builder = new AlipayTradeRefundRequestBuilder()
                .setOutTradeNo(orderNo)
                .setRefundAmount(order.getOfficialReceipts().toString())
                .setRefundReason("订单退款")
                .setOutRequestNo(String.valueOf(System.nanoTime()))
                .setStoreId(String.valueOf(order.getUserId()));
        AlipayF2FRefundResult result = alipayTradeService.tradeRefund(builder);
        switch (result.getTradeStatus()) {
            case SUCCESS:
                if (!payService.changeOrderToRefund(order)) {
                    return ResultUtil.error("订单状态异常!");
                }
                logger.info("支付宝退款成功: )");
                return ResultUtil.success("支付宝退款成功: )");

            case FAILED:
                logger.error("支付宝退款失败!!!");
                return ResultUtil.error("支付宝退款失败!!!");

            case UNKNOWN:
                logger.error("系统异常，订单退款状态未知!!!");
                return ResultUtil.error("系统异常，订单退款状态未知!!!");

            default:
                logger.error("不支持的交易状态，交易返回异常!!!");
                return ResultUtil.error("不支持的交易状态，交易返回异常!!!");
        }

    }


    /**
     * 扫码付异步结果通知,支付宝扫码可以无视
     *
     * @param request
     */
    @RequestMapping("/alipay/notify")
    @ApiOperation("支付宝异步结果通知")
    public Result notify(HttpServletRequest request) throws AlipayApiException {
        // 一定要验签，防止黑客篡改参数
        Map<String, String[]> parameterMap = request.getParameterMap();
        parameterMap.forEach((key, value) -> System.out.println(key + "=" + value[0]));

        // https://docs.open.alipay.com/54/106370
        // 获取支付宝POST过来反馈信息
        Map<String, String> params = new HashMap<>();
        Map requestParams = request.getParameterMap();
        for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            params.put(name, valueStr);
        }

        boolean flag = AlipaySignature.rsaCheckV1(params,
                aliPayProperties.getAlipayPublicKey(),
                aliPayProperties.getCharset(),
                aliPayProperties.getSignType());

        if (flag) {
            return ResultUtil.success("成功.");
        }

        return ResultUtil.error("失败.");
    }

    @RequestMapping("/weixin/query")
    @ApiOperation("微信订单查询")
    public Result weixinOrderQuery(String orderNo) {

        Map<String, String> data = new HashMap<>();
        data.put("out_trade_no", orderNo);
        try {
            Map<String, String> result = wxPay.orderQuery(data);
            return ResultUtil.success("成功", result);
        } catch (Exception e) {
            return ResultUtil.error(e.getMessage());
        }
    }


    @GetMapping("/pay")
    @ApiOperation("微信订单查询")
    public Result weixinOrderQuerys() {
        int rs=0;
        List<String> string1=pay.select1();
        List<String> string2=pay.select2();
        for (String string:string2){
            for (String s:string1){
                if (!"".equals(string)&&null!=string){
                    if (string.equals(s)){
                        int index = pay.select3(s);
                        String name =string;
                        rs +=pay.update(name,index);
                        break;
                    }
                }
            }
        }

        return ResultUtil.success("成功", rs);

    }

    private AdminUser getUserById(int id) {
        AdminUser user = userMapper.selectById(id);
        Preconditions.checkNotNull(user, "未发现对应的用户");
        if (user.getStatus() != 0) {
            throw new RuntimeException("用户未被启用");
        }
        return user;
    }
}
